/**
 *******************************************************************************
 * @file    dpm32m0xx_adc.c.
 *
 * @brief   Source file for ADC firmware driver.
 *          This file provides firmware functions to manage the following
 *          functionalities of the Analog to Digital Convertor (ADC) peripheral:
 *           + Initialization and Configuration
 *           + Analog Watchdog configuration
 *           + Temperature Sensor & Vrefint (Voltage Reference internal) & VBAT
 *             management
 *           + Regular Channels Configuration
 *           + DMA Configuration
 *           + Injected channels Configuration
 *           + Interrupts and flags management
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 * @verbatim
 ===============================================================================
                       ##### How to use this driver #####
 ===============================================================================
    [..]
      (#) Enable The ADC controller clock
          using RCC_APBPeriphClockCmd(RCC_APB_PERIPH_ADC, ENABLE).

      (#) ADC pins configuration:
        (+) Enable the clock for the ADC GPIOs using the following function:
            RCC_AHBPeriphClockCmd(RCC_AHB_PERIPH_GPIO, ENABLE).
        (+) Configure these ADC pins in analog mode using GPIO_Init().
        (+) Configure these ADC pins analog alternate function using
            GPIO_AnaAFConfig().

      (#) Configure the ADC sync trigger, reference voltage, clock division,
          PGA channel, sample cycle and sample accuracy using the ADCCOM_Init()
          function.

      (#) Configure the ADC channel buffer, over sample, choose sample time and
          offset value using the ADCCOM_ChannelConfig() function.

      (#) Configure the ADC trigger mode, continue sample wait cycles, trigger
          source and scan sample length using the ADC_Init() function.

      (#) Configure the ADC channel data alignment, data sign and watchdog using
          the ADC_ChannelConfig() function.

      (#) Activate the ADC peripheral using ADC_Cmd() function.

    *** Regular channels group configuration ***
    ============================================
    [..]
      (#) Software trigger sample mode:
        (+) To configure the ADC regular channels group features, use
            ADC_Init() and ADC_ChannelConfig() functions.
        (+) To configure the ADC software trigger channel, use the
            ADC_SoftwareTrigConfig() function.
        (+) To start ADC conversion , use the ADC_StartConversion() functions.
        (+) To read the ADC converted values, use the ADC_GetSingleData()
            function.
        (+) To stop ADC conversion , use the ADC_StopConversion() functions.

      (#) Hardware trigger sample mode:
        (+) To configure the ADC regular channels group features, use
            ADC_Init() and ADC_ChannelConfig() functions.
        (+) To configure the ADC hardware trigger features, use the
            ADC_HardwareTrigConfig() function.
        (+) To activate the ADC hardware trigger, use the ADC_HardwareTrigCmd()
            function.
        (+) To read the ADC converted values, use the ADC_GetHWTrig0Data() and
            ADC_GetHWTrig1Data() function.

      (#) Scan sampling mode:
        (+) To configure the ADC regular channels group features, use
            ADC_Init() and ADC_ChannelConfig() functions.
        (+) To configure the ADC scan sampling features, use the
            ADC_ScanChannelConfig() function.
        (+) To read the ADC converted values, use the ADC_GetScanData() function.

    *** DMA for ADC sample configuration ***
    ============================================
    [..]
      (#) To enable the DMA mode for regular channels group, use the
          ADC_DMACmd() function.

    *** Injected channels group configuration ***
    =============================================
    [..]
      (#) To configure the ADC regular channels group features, use
          ADC_Init() and ADC_ChannelConfig() functions.

      (#) To configure the ADC inject features, use the
          ADC_InjectChannelConfig() function.

      (#) To start ADC conversion , use the ADC_InjectStart() functions.

      (#) To read the ADC converted values, use the ADC_GetInjectData()
          function.

    *** Analog watchdog configuration ***
    =============================================
    [..]
      (#) To configure the ADC analog watchdog features, use
          ADC_AnalogWatchdogConfig() functions.

      (#) To activate the ADC analog watchdog, use the
          ADC_AnalogWatchdogChannelCmd() function.

    *** ADC interrupt configuration ***
    =============================================
    [..]
      (#) To activate the ADC interrupt, use ADC_IntCmd() functions.

      (#) Check on ADC interrupt enable flags using the function
          ADC_GetIntCmdStatus().

      (#) Check on ADC interrupt occur flags using the function
          ADC_GetIntFlagStatus().

      (#) Clear ADC interrupt flags using the function ADC_ClearIntFlag().

 * @endverbatim
 *******************************************************************************/

#include "dpm32m0xx_adc.h"



/**
 *******************************************************************************
 * @brief   Deinitializes ADC control registers to their default reset values.
 * @retval  None.
********************************************************************************/
void ADCCOM_DeInit(void)
{
  unsigned char i = 0;

  /* Set ADC control register to reset value */
  ADC_COM->CR = 0x0210FFFFUL;

  /* Set ADC cnannel sample time register to reset value */
  ADC_COM->SMPT = 0x00000000UL;

  /* Set ADC channel oversampling and precision register to reset value */
  ADC_COM->SMPC = 0x00000000UL;

  /* Set ADC channel offset value register to reset value */
  for(i = 0; i < 16; i++)
  {
    ADC_COM->CH_OFFSET[i] = 0x00000000UL;
  }
}

/**
 *******************************************************************************
 * @brief   Configure each ADC with same configuration parameters.
 * @param   [in]  ADCCOM_InitType: @ref ADCCOM_InitTypeStruct.
 *                @arg SyncTrig:software synchronization triggers of each ADC.
 *                     This parameter can be: ENABLE or DISABLE.
 *                @arg AdcSpeed:sampling current of each ADC.Setting to 1 can improve ADC
 *                     sampling accuracy,but it will increase current.
 *                @arg Vref:reference source select of each ADC. @ref ADC_Vref.
 *                @arg ClkDiv:clock division of each ADC. @ref ADC_Clk_Div.
 *                @arg PGASel:PGA channel enable.The parameter can be one or more of enum.
 *                     @ref ADC_PGASelEnum.
 *                @arg SampleTime0: sample time selection 0 of each ADC.  @ref ADC_SampleTimeEnum.
 *                @arg SampleTime1: sample time selection 1 of each ADC. @ref ADC_SampleTimeEnum.
 *                @arg OversampleRatio:oversampling ratio of each ADC.If not needed,it can be ignored.
 *                     @ref ADC_Oversampling_Ratio.
 *                @arg OversampleAccuracy:oversampling accuracy of each ADC. @ref ADC_Oversample_Accuracy.
 *                @arg SampleAccuracy:all of ADC normal sampling accuracy. @ref ADC_Sample_Accuracy.
 * @retval  None.
 ******************************************************************************/
void ADCCOM_Init(ADCCOM_InitTypeStruct *ADCCOM_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_ADC_VERF(ADCCOM_InitType->Vref));
  PARAM_ASSERT(IS_ADC_PGA_SEL(ADCCOM_InitType->PGASel));
  PARAM_ASSERT(IS_ADC_SAMPLE_TIME(ADCCOM_InitType->SampleTime0));
  PARAM_ASSERT(IS_ADC_SAMPLE_TIME(ADCCOM_InitType->SampleTime1));
  PARAM_ASSERT(IS_ADC_PRESC(ADCCOM_InitType->ClkDiv));
  PARAM_ASSERT(IS_ADC_OVERSAMPLE_RATIO(ADCCOM_InitType->OversampleRatio));
  PARAM_ASSERT(IS_ADC_OVERSAMPLE_ACCURACY(ADCCOM_InitType->OversampleAccuracy));
  PARAM_ASSERT(IS_ADC_SAMPLING_ACCURACY(ADCCOM_InitType->SampleAccuracy));

  /* MASK BUFEN[15:0]. */
  tmpReg = ADC_COM->CR & 0X0000FFFF;

#if defined (DPM32M03x)
  /* Clear PGA_SEL0,PGA_SEL1,PGA_SEL2,PGA_SEL3,PRESC,VREF_SEL,ADC_SPEED,SYNC_SW_TRIG bits. */
  tmpReg &= ~(uint32_t)(ADC_COM_CR_PGA_SEL0_Msk | ADC_COM_CR_PGA_SEL1_Msk | ADC_COM_CR_PGA_SEL3_Msk \
                        | ADC_COM_CR_PRESC_Msk | ADC_COM_CR_VREF_SEL_Msk | ADC_COM_CR_SPEED_Msk);
#elif defined (DPM32M05x)
  /* Clear PGA_SEL0,PGA_SEL1,PGA_SEL2,PGA_SEL3,PRESC,VREF_SEL,ADC_SPEED,SYNC_SW_TRIG bits. */
  tmpReg &= ~(uint32_t)(ADC_COM_CR_PGA_SEL0_Msk | ADC_COM_CR_PGA_SEL1_Msk | ADC_COM_CR_PGA_SEL2_Msk \
                        | ADC_COM_CR_PGA_SEL3_Msk | ADC_COM_CR_PRESC_Msk | ADC_COM_CR_VREF_SEL_Msk \
                        | ADC_COM_CR_SPEED_Msk);
#else
  /* Clear PGA_SEL0,PGA_SEL1,PGA_SEL2,PGA_SEL3,PRESC,VREF_SEL,ADC_SPEED,SYNC_SW_TRIG bits. */
  tmpReg &= ~(uint32_t)(ADC_COM_CR_PGA_SEL0_Msk | ADC_COM_CR_PGA_SEL1_Msk | ADC_COM_CR_PGA_SEL2_Msk \
                        | ADC_COM_CR_PGA_SEL3_Msk | ADC_COM_CR_PRESC_Msk | ADC_COM_CR_VREF_SEL_Msk \
                        | ADC_COM_CR_SPEED_Msk | ADC_COM_CR_SYNC_TRIG_Msk);
#endif /* DPM32M03x */

  /* Set PGA_SEL0,PGA_SEL1,PGA_SEL2,PGA_SEL3 bits according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->PGASel;

  /* Set PRESC[2:0] bits according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->ClkDiv;

  /* Set VREF_SEL bit according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->Vref;

  /* Set ADC_SPEED bit according to ADCCOM_InitType. */
  tmpReg |= (uint32_t)(ADCCOM_InitType->AdcSpeed << ADC_COM_CR_SPEED_Pos);

#if defined (DPM32M08x)
  /* Set SYNC_SW_TRIG bit according to ADCCOM_InitType. */
  tmpReg |= (uint32_t)(ADCCOM_InitType->SyncTrig << ADC_COM_CR_SYNC_TRIG_Pos);
#endif /* DPM32M08x */

  ADC_COM->CR = tmpReg;

  /* MASK sampling time select. */
  tmpReg = ADC_COM->SMPT & 0X0000FFFF;

  /* Clear SMPT_SMPT0,SMPT_SMPT1 bits. */
  tmpReg &= ~(uint32_t)(ADC_COM_SMPT_SMPT0_Msk | ADC_COM_SMPT_SMPT1_Msk);

  /* Set SMPT_SMPT0[2:0] bits according to ADCCOM_InitType. */
  tmpReg |= (uint32_t)(ADCCOM_InitType->SampleTime0 << ADC_COM_SMPT_SMPT0_Pos);

  /* Set SMPT_SMPT1[2:0] bits according to ADCCOM_InitType. */
  tmpReg |= (uint32_t)(ADCCOM_InitType->SampleTime1 << ADC_COM_SMPT_SMPT1_Pos);

  ADC_COM->SMPT = tmpReg;

  /* MASK over sampling enable. */
  tmpReg = ADC_COM->SMPC & 0X0000FFFF;

  /* Clear SMPC_NORM_RES,SMPC_OVS_RES,SMPC_OVS_RATE bits. */
  tmpReg &= ~(uint32_t)(ADC_COM_SMPC_NORM_RES_Msk | ADC_COM_SMPC_OVS_RES_Msk | ADC_COM_SMPC_OVS_RATE_Msk);

  /* Set SMPC_NORM_RES[2:0] bits according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->SampleAccuracy;

  /* Set SMPC_OVS_RES[2:0] bits according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->OversampleAccuracy;

  /* Set SMPC_OVS_RATE[1:0] bits according to ADCCOM_InitType. */
  tmpReg |= ADCCOM_InitType->OversampleRatio;

  ADC_COM->SMPC = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Initialize the ADCCOM_InitType with default parameters.
 * @param   [in]  ADCCOM_InitType: Pointer to a ADCCOM_InitTypeStruct structure
 *                which will be initialized.
 * @retval  None.
 ******************************************************************************/
void ADCCOM_StructInit(ADCCOM_InitTypeStruct *ADCCOM_InitType)
{
  ADCCOM_InitType->SyncTrig = DISABLE;
  ADCCOM_InitType->AdcSpeed = 1;
  ADCCOM_InitType->Vref = ADC_VREF_AVDD;
  ADCCOM_InitType->ClkDiv = ADC_CLK_DIV1;
  ADCCOM_InitType->PGASel = ADC_PGA_SEL_NONE;
  ADCCOM_InitType->SampleTime0 = ADC_SAMPLE_TIME_2Cycles;
  ADCCOM_InitType->SampleTime1 = ADC_SAMPLE_TIME_2Cycles;
  ADCCOM_InitType->OversampleRatio = ADC_Oversample_Ratio_4x;
  ADCCOM_InitType->OversampleAccuracy = ADC_Oversample_Accuracy_12Bit;
  ADCCOM_InitType->SampleAccuracy = ADC_Sample_Accuracy_6Bit;
}

/**
 *******************************************************************************
  * @brief  Configure each ADC with same channel configuration parameters.
  * @param  ADCCOM_Channel. @ref ADCCOM_ChannelStruct
  *         @arg Channel:channel of each ADC. @ref ADC_Channel
  *         @arg BufferEnable:input channel buffer select of each ADC.
  *         @arg OversampleEnable:channel over sampling of each ADC enable or disable.
  *         @arg SampleTimeSel:sampling time select of each ADC. @ref ADC_SampleTimeSelEnum
  *         @arg Offset.channel offset of each ADC.This parameter can be a number between 0x0000 and 0xFFF
  * @retval None
 ******************************************************************************/
void ADCCOM_ChannelConfig(ADCCOM_ChannelStruct* ADCCOM_Channel)
{
  /* ADC common input channel buffer configuration. */
  if(ADCCOM_Channel->BufferEnable != DISABLE)
  {
    ADC_COM->CR |= (ADC_COM_CR_BUFEN0_Msk << ADCCOM_Channel->Channel);
  }
  else
  {
    ADC_COM->CR &= ~(ADC_COM_CR_BUFEN0_Msk << ADCCOM_Channel->Channel);
  }

  /* ADC common channel sampling time selection. */
  if(ADCCOM_Channel->SampleTimeSel == ADC_SAMPLE_TIME_SEL0)
  {
    ADC_COM->SMPT &= ~(ADC_COM_SMPT_SMPT_SEL0_Msk << ADCCOM_Channel->Channel);
  }
  else
  {
    ADC_COM->SMPT |= (ADC_COM_SMPT_SMPT_SEL0_Msk << ADCCOM_Channel->Channel);
  }

  /* ADC common channel over sampling configuration. */
  if(ADCCOM_Channel->OversampleEnable != DISABLE)
  {
    ADC_COM->SMPC |= (ADC_COM_SMPC_OVSEN0_Msk << ADCCOM_Channel->Channel);
  }
  else
  {
    ADC_COM->SMPC &= ~(ADC_COM_SMPC_OVSEN0_Msk << ADCCOM_Channel->Channel);
  }

  /* ADC common channel offset value configuration. */
  ADC_COM->CH_OFFSET[ADCCOM_Channel->Channel] = ADCCOM_Channel->Offset & ADC_COM_CH_OFFSET_VALUE_Msk;
}

/**
 *******************************************************************************
 * @brief   Initialize the ADCCOM_Channel with default parameters.
 * @param   [in]  ADCCOM_Channel: Pointer to a ADCCOM_ChannelStruct structure
 *                which will be initialized.
 * @retval  None.
 ******************************************************************************/
void ADCCOM_ChannelStructInit(ADCCOM_ChannelStruct *ADCCOM_Channel)
{
  ADCCOM_Channel->Channel = ADC_Channel_0;
  ADCCOM_Channel->BufferEnable = DISABLE;
  ADCCOM_Channel->OversampleEnable = DISABLE;
  ADCCOM_Channel->SampleTimeSel = ADC_SAMPLE_TIME_SEL0;
  ADCCOM_Channel->Offset = 0;
}

/**
 *******************************************************************************
 * @brief   Deinitializes ADC peripheral registers to their default reset values.
 * @retval  None.
********************************************************************************/
void ADC_DeInit(ADC_Type* ADCx)
{
  /* Clear all interrupt flag. */
  ADCx->ISR = 0xFFFF7DF7UL;

  /* Set ADC interrupt enable register to reset value */
  ADCx->IE = 0x00000000UL;

  /* Set ADC configuration register to reset value */
  ADCx->CFG = 0x00000000UL;

  /* Set ADC format config register to reset value */
  ADCx->FMT_CR = 0x00000000UL;

  /* Set ADC trigger control register to reset value */
  ADCx->TRIG_CR = 0x00000000UL;

  /* Set ADC inject control register to reset value */
  ADCx->INJ_CR = 0x00000000UL;

  /* Set ADC anagle watch dog enable register to reset value */
  ADCx->AWD_CR = 0x00000000UL;

  /* Set ADC anagle watch dog trigger register to reset value */
  ADCx->AWD_TH = 0x00000000UL;

  /* Set ADC channel sample sequence register 0 to reset value */
  ADCx->SCAN_SQR0 = 0x00000000UL;

  /* Set ADC channel sample sequence register 1 to reset value */
  ADCx->SCAN_SQR1 = 0x00000000UL;
}

/**
 *******************************************************************************
  * @brief  ADC initialization.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_InitType: @ref ADC_InitTypeStruct.
  *         @arg TrigMode:ADCx trigger mode. @ref ADC_Trig_Mode
  *         @arg ContinueWait:Software triggered channel continuous data collection
  *              waiting time. @ref ADC_Continue_Wait
  *         @arg SoftTrigChannel.Software trigger single channel selection. @ref ADC_Channel
  *         @arg HardwareTrig0.Hardware trigger 0 parameter.
  *              @arg TrigSource.Trigger source. @ref ADC_Trig_Source
  *              @arg TrigChannel.Trigger channel. @ref ADC_Channel
  *              @arg TrigEnable.Enable or disable hardware trigger.
  *         @arg HardwareTrig1.Hardware trigger 1 parameter.
  *              Same as HardwareTrig0.
  *         @arg ScanChannelLen: Scan sequence length.This parameter can be a number between 1 and 14.
  * @retval None
 ******************************************************************************/
void ADC_Init(ADC_Type* ADCx, ADC_InitTypeStruct* ADC_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_ADC_PERIPH(ADCx));
  PARAM_ASSERT(IS_ADC_TRIG_MODE(ADC_InitType->TrigMode));
  PARAM_ASSERT(IS_ADC_CONTINUE_WAIT(ADC_InitType->ContinueWait));

  /* Set TRIG_MODE[2:0] bits according to ADC_InitType. */
  tmpReg |= ADC_InitType->TrigMode;

  /* Set CONTINUE_WAIT[2:0] bits according to ADC_InitType. */
  tmpReg |= ADC_InitType->ContinueWait;

  /* Set SW_TRIG_CH[3:0] bits according to ADC_InitType. */
  tmpReg |= (ADC_InitType->SoftTrigChannel << ADC_TRIG_CR_SW_CH_Pos);

  /* Set HW_TRIG0_CH[3:0] bits according to ADC_InitType. */
  tmpReg |= (ADC_InitType->HardwareTrig0.TrigChannel << ADC_TRIG_CR_HW0_CH_Pos);

  /* Set HW_TRIG0_SRC[3:0] bits according to ADC_InitType. */
  tmpReg |= (ADC_InitType->HardwareTrig0.TrigSource << ADC_TRIG_CR_HW0_SRC_Pos);

  /* Set HW_TRIG0_EN bit according to ADC_InitType. */
  if(ADC_InitType->HardwareTrig0.TrigEnable != DISABLE)
  {
    tmpReg |= ADC_TRIG_CR_HW0_EN_Msk;
  }

  /* Set HW_TRIG1_CH[3:0] bits according to ADC_InitType. */
  tmpReg |= (ADC_InitType->HardwareTrig1.TrigChannel << ADC_TRIG_CR_HW1_CH_Pos);

  /* Set HW_TRIG1_SRC[3:0] bits according to ADC_InitType. */
  tmpReg |= (ADC_InitType->HardwareTrig1.TrigSource << ADC_TRIG_CR_HW1_SRC_Pos);

  /* Set HW_TRIG1_EN bit according to ADC_InitType. */
  if(ADC_InitType->HardwareTrig1.TrigEnable != DISABLE)
  {
    tmpReg |= ADC_TRIG_CR_HW1_EN_Msk;
  }

  ADCx->TRIG_CR = tmpReg;

  tmpReg = ADCx->SCAN_SQR0;

  /* Clear SCAN_LEN bits. */
  tmpReg &= ~ADC_SCAN_SQR0_LEN_Msk;

  if(ADC_InitType->ScanChannelLen != 0)
  {
    /* Set SCAN_LEN bit according to ADC_InitType. */
    tmpReg |= ((ADC_InitType->ScanChannelLen - 1) << ADC_SCAN_SQR0_LEN_Pos);
  }

  ADCx->SCAN_SQR0 = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Initialize the ADC_InitType with default parameters.
 * @param   [in]  ADC_InitType Pointer to a ADC_InitTypeStruct structure which will be initialized.
 * @retval  None.
 ******************************************************************************/
void ADC_StructInit(ADC_InitTypeStruct *ADC_InitType)
{
  ADC_InitType->TrigMode = ADC_TRIG_SW_SINGLE_CONV;
  ADC_InitType->ContinueWait = ADC_CONTINUE_WAIT_CYCLE_0;
  ADC_InitType->SoftTrigChannel = ADC_Channel_0;
  ADC_InitType->HardwareTrig0.TrigSource = ADC_TRIG_SOURCE_TIMER0;
  ADC_InitType->HardwareTrig0.TrigChannel = ADC_Channel_0;
  ADC_InitType->HardwareTrig0.TrigEnable = DISABLE;
  ADC_InitType->HardwareTrig1.TrigSource = ADC_TRIG_SOURCE_TIMER0;
  ADC_InitType->HardwareTrig1.TrigChannel = ADC_Channel_0;
  ADC_InitType->HardwareTrig1.TrigEnable = DISABLE;
  ADC_InitType->ScanChannelLen = 0;
}

/**
 *******************************************************************************
  * @brief  Enable or disable ADC.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  NewState: new state of the specified ADC.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
 ******************************************************************************/
void ADC_Cmd(ADC_Type* ADCx, FunctionalState NewState)
{
  if(NewState != DISABLE)
  {
    /* Enable ADC peripheral. */
    ADCx->CFG |= ADC_CFG_ADC_EN_Msk;
  }
  else
  {
    /* Disable ADC peripheral. */
    ADCx->CFG &= ~ADC_CFG_ADC_EN_Msk;
  }
}

/**
 *******************************************************************************
  * @brief  ADC channel configuration.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_Channel: @ref ADC_ChannelStruct.
  *         @arg channel:ADC channel. @ref ADC_Channel
  *         @arg DataAlign:Data align mode. @ref ADC_DataAlignEnum
  *         @arg DataSign:Data sign. @reg ADC_DataSignEnum
  *         @arg AWDEnable:Analog watchdog enable
  * @retval None
 ******************************************************************************/
void ADC_ChannelConfig(ADC_Type* ADCx, ADC_ChannelStruct* ADC_Channel)
{
  /* Configure ADC selected channel data alignment. */
  if(ADC_Channel->DataAlign == ADC_DATA_ALIGN_LEFT)
  {
    ADCx->FMT_CR |= (ADC_FMT_CR_ALIGN0_Msk << ADC_Channel->Channel);
  }
  else
  {
    ADCx->FMT_CR &= ~(ADC_FMT_CR_ALIGN0_Msk << ADC_Channel->Channel);
  }

  /* Configure ADC selected channel data sign. */
  if(ADC_Channel->DataSign == ADC_DATA_SIGNED)
  {
    ADCx->FMT_CR |= (ADC_FMT_CR_SIGN0_Msk << ADC_Channel->Channel);
  }
  else
  {
    ADCx->FMT_CR &= ~(ADC_FMT_CR_SIGN0_Msk << ADC_Channel->Channel);
  }

  /* Configure ADC selected channel analog watchdog enable. */
  if(ADC_Channel->AWDEnable != DISABLE)
  {
    ADCx->AWD_CR |= (ADC_AWD_CR_EN0_Msk << ADC_Channel->Channel);
  }
  else
  {
    ADCx->AWD_CR &= ~(ADC_AWD_CR_EN0_Msk << ADC_Channel->Channel);
  }
}

/**
 *******************************************************************************
 * @brief   Initialize the ADC_Channel with default parameters.
 * @param   [in]  ADC_Channel Pointer to a ADC_ChannelStruct structure which will be initialized.
 * @retval  None.
 ******************************************************************************/
void ADC_ChannelStructInit(ADC_ChannelStruct *ADC_Channel)
{
  ADC_Channel->Channel = ADC_Channel_0;
  ADC_Channel->DataAlign = ADC_DATA_ALIGN_RIGHT;
  ADC_Channel->DataSign = ADC_DATA_UNSIGNED;
  ADC_Channel->AWDEnable = DISABLE;
}

/**
 *******************************************************************************
  * @brief  ADCx trig mode config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_TrigMode: ADC trig mode.
  *         @arg ADC_TRIG_SW_SINGLE_CONV. ADC software triggered single channel conversion.
  *         @arg ADC_TRIG_SW_SINGLE_CONTINUOUS_CONV. ADC software triggered single
  *              channel continuous conversion.
  *         @arg ADC_TRIG_SW_SEQ_CONTINUOUS_CONV. ADC software triggered sequence
  *              continuous scan.
  *         @arg ADC_TRIG_HW_SINGLE_CONV. ADC hardware triggered single channel conversion.
  *         @arg ADC_TRIG_HW_SEQ_CONV. ADC hardware triggered single sequence scan
  * @retval None
 ******************************************************************************/
void ADC_TrigModeConfig(ADC_Type* ADCx, uint32_t ADC_TrigMode)
{
  uint32_t tmpReg = 0UL;

  tmpReg = ADCx->TRIG_CR;

  /* Clear TRIG_CR_TRIG_MODE[2:0] bits. */
  tmpReg &= ~ADC_TRIG_CR_MODE_Msk;

  /* Set TRIG_CR_TRIG_MODE[2:0] bits according to ADC_TrigMode. */
  tmpReg |= ( ADC_TrigMode );

  ADCx->TRIG_CR = tmpReg;
}

/**
 *******************************************************************************
  * @brief  Enables or disables the specified ADC interrupts.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_Int: specifies the ADC interrupt sources to be enabled or disabled.
  *          This parameter can be one of the following values:
  *            @arg ADC_INT_TYPE_EOS: ADC scan mode complete interrupt
  *            @arg ADC_INT_TYPE_EOT0: Hardware trigger 0 single channel complete interrupt
  *            @arg ADC_INT_TYPE_EOT1: Hardware trigger 1 single channel complete interrupt
  *            @arg ADC_INT_TYPE_EOC: Software single channel complete interrupt interrupt
  *            @arg ADC_INT_TYPE_EOI: Inject sampling complete interrupt
  *            @arg ADC_INT_TYPE_OVR: Data overrun interrupt
  *            @arg ADC_INT_TYPE_AWD: Analog watchdog interrupt
  * @param  NewState: new state of the specified ADC interrupts.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
 ******************************************************************************/
void ADC_IntCmd(ADC_Type* ADCx,uint32_t ADC_Int, FunctionalState NewState)
{
  /* Configure ADC specified interrupt enable. */
  if(NewState != DISABLE)
  {
    ADCx->IE |= ADC_Int;
  }
  else
  {
    ADCx->IE &= ~(ADC_Int);
  }
}

/**
 *******************************************************************************
 * @brief   Get the specified ADC interrupt status.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_Int: specifies the ADC interrupt sources to be enabled or disabled.
  *          This parameter can be one of the following values:
  *            @arg ADC_INT_TYPE_EOS: ADC saan mode complete interrupt
  *            @arg ADC_INT_TYPE_EOT0: Hardware trigger 0 single channel complete interrupt
  *            @arg ADC_INT_TYPE_EOT1: Hardware trigger 1 single channel complete interrupt
  *            @arg ADC_INT_TYPE_EOC: Software single channel complete interrupt interrupt
  *            @arg ADC_INT_TYPE_EOI: Inject sampling complete interrupt
  *            @arg ADC_INT_TYPE_OVR: Data overrun interrupt
  *            @arg ADC_INT_TYPE_AWD: Analog watchdog interrupt
 * @retval  FunctionalState: The UART interrupt state(ENABLE or DISABLE).
 ******************************************************************************/
FunctionalState ADC_GetIntCmdStatus(ADC_Type *ADCx, uint32_t ADC_Int)
{
  FunctionalState state = DISABLE;

  if (RESET != (ADCx->IE & ADC_Int))
  {
    /* Interrupt is enable. */
    state = ENABLE;
  }
  else
  {
    /* Interrupt is disbale. */
    state = DISABLE;
  }

  /* Return the status of the interrupt enable bit. */
  return state;
}

/**
 *******************************************************************************
  * @brief  Get ADC interrupt flag.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_IntFlag: specifies the flag to check.
  *          This parameter can be one of the following values:
  *            @arg ADC_INT_FLAG_EO_SUM: End of data flag.When the EOI,EOC,EOT1,
  *                   EOT0 and EOS status flags exist at 1,the bit will set 1 by hardware.
  *            @arg ADC_INT_FLAG_OVR_SUM: Data overrun flag.When the OVR_EOI,OVR_EOC,
  *                   OVR_EOT1,OVR_EOT0 and OVR_EOS status flag exist at 1,the bit will set 1 by hardware
  *            @arg ADC_INT_FLAG_AWG_SUM: Analog watchdog flag.When AWD_CH0-15
  *                   status flags exist at 1,the bit will set 1 by hardware.
  *            @arg ADC_INT_FLAG_EOS: End of sequence flag
  *            @arg ADC_INT_FLAG_EOT0: End of trigger 0 flag
  *            @arg ADC_INT_FLAG_EOT1: End of trigger 1 flag
  *            @arg ADC_INT_FLAG_EOC: End of conversion flag
  *            @arg ADC_INT_FLAG_EOI: End of inject conversion flag
  *            @arg ADC_INT_FLAG_OVR_EOS: ADC scan data overrun flag
  *            @arg ADC_INT_FLAG_OVR_EOT0: ADC trigger 0 data overrun
  *            @arg ADC_INT_FLAG_OVR_EOT1: ADC trigger 1 data overrun
  *            @arg ADC_INT_FLAG_OVR_EOC: ADC single data overrun
  *            @arg ADC_INT_FLAG_OVR_EOI: ADC inject data overrun
  *            @arg ADC_INT_FLAG_AWD_CHx: Analog watchdog 0-15 flag
  * @retval The new state of ADC_FLAG (SET or RESET).
 ******************************************************************************/
FlagState ADC_GetIntFlagStatus(ADC_Type* ADCx, uint32_t ADC_IntFlag)
{
  FlagState state = RESET;

  if(RESET != (ADCx->ISR & ((uint32_t)ADC_IntFlag)))
  {
    /* Interrupt has occurred. */
    state = SET;
  }
  else
  {
    /* Interrupt has not occurred. */
    state = RESET;
  }

  /* Return the status of the interrupt flag. */
  return state;
}

/**
 *******************************************************************************
  * @brief  Clear ADC interrupt flag.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_IntFlag: specifies the flag to check.
  *          This parameter can be one of the following values:
  *            @arg ADC_INT_FLAG_EO_SUM: End of data flag.When the EOI,EOC,EOT1,
  *                   EOT0 and EOS status flags exist at 1,the bit will set 1 by hardware.
  *            @arg ADC_INT_FLAG_OVR_SUM: Data overrun flag.When the OVR_EOI,OVR_EOC,
  *                   OVR_EOT1,OVR_EOT0 and OVR_EOS status flag exist at 1,the bit will set 1 by hardware
  *            @arg ADC_INT_FLAG_AWG_SUM: Analog watchdog flag.When AWD_CH0-15
  *                   status flags exist at 1,the bit will set 1 by hardware.
  *            @arg ADC_INT_FLAG_EOS: End of sequence flag
  *            @arg ADC_INT_FLAG_EOT0: End of trigger 0 flag
  *            @arg ADC_INT_FLAG_EOT1: End of trigger 1 flag
  *            @arg ADC_INT_FLAG_EOC: End of conversion flag
  *            @arg ADC_INT_FLAG_EOI: End of inject conversion flag
  *            @arg ADC_INT_FLAG_OVR_EOS: ADC scan data overrun flag
  *            @arg ADC_INT_FLAG_OVR_EOT0: ADC trigger 0 data overrun
  *            @arg ADC_INT_FLAG_OVR_EOT1: ADC trigger 1 data overrun
  *            @arg ADC_INT_FLAG_OVR_EOC: ADC single data overrun
  *            @arg ADC_INT_FLAG_OVR_EOI: ADC inject data overrun
  *            @arg ADC_INT_FLAG_AWD_CHx: Analog watchdog 0-15 flag
  * @retval None.
 ******************************************************************************/
void ADC_ClearIntFlag(ADC_Type* ADCx, uint32_t ADC_IntFlag)
{
  /* Clear ADC interrupt flag. */
  ADCx->ISR = ADC_IntFlag;
}

#if defined (DPM32M08x) || defined (DPM32M05x)
/**
 *******************************************************************************
  * @brief  Enables or disables the specified ADC DMA request.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_DMA: specifies the ADC DMA request to be enabled or disabled.
  *          This parameter can be one of the following values:
  *            @arg ADC_DMA_EOC: ADC single conversion complete dma request
  *            @arg ADC_DMA_EOS: ADC sequence conversion complete dma request
  *            @arg ADC_DMA_EOT0: Hardware trigger 0 single channel complete dma request
  *            @arg ADC_DMA_EOT1: Hardware trigger 1 single channel complete dma request
  * @param  NewState: new state of the specified ADC interrupts.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
 ******************************************************************************/
void ADC_DMACmd(ADC_Type* ADCx,uint32_t ADC_DMA, FunctionalState NewState)
{
  /* Configure ADC specified DMA enable. */
  if(NewState != DISABLE)
  {
    ADCx->CFG |= ADC_DMA;
  }
  else
  {
    ADCx->CFG &= ~(ADC_DMA);
  }
}
#endif  /* DPM32M08x || DPM32M05x */

/**
 *******************************************************************************
  * @brief  Start Conversion for the selected ADC channels.
  * @note   In continuous mode, SW_TRIG_START is not cleared by hardware
  *         because the sequence is automatic relaunched
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval None
 ******************************************************************************/
void ADC_StartConversion(ADC_Type* ADCx)
{
  ADCx->TRIG_CR |= ADC_TRIG_CR_SW_START_Msk;
}

/**
 *******************************************************************************
  * @brief  Stop Conversion.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval None
 ******************************************************************************/
void ADC_StopConversion(ADC_Type* ADCx)
{
  ADCx->TRIG_CR |= ADC_TRIG_CR_STOP_Msk;
}

/**
 *******************************************************************************
  * @brief  ADCx software trigger channel config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_Ch:Software trigger channel. @ref ADC_Channel
  * @retval None
 ******************************************************************************/
void ADC_SoftwareTrigConfig(ADC_Type* ADCx, uint8_t ADC_Ch)
{
  ADCx->TRIG_CR &= ~ADC_TRIG_CR_SW_CH_Msk;

  ADCx->TRIG_CR |= (uint32_t)(ADC_Ch << ADC_TRIG_CR_SW_CH_Pos);
}

/**
 *******************************************************************************
  * @brief  ADCx hardware trigger enable.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  HWTrigX:Hardware trigger 0 or 1 select. @ref ADC_HWTrigX
  * @param  NewState:Enable or disable hardware trigger.
  * @retval None
 ******************************************************************************/
void ADC_HardwareTrigCmd(ADC_Type* ADCx, ADC_HWTrigX HWTrigX, FunctionalState NewState)
{
  if(NewState != DISABLE)
  {
    ADCx->TRIG_CR |= ((HWTrigX == ADC_HW_TRIG0) ? (ADC_TRIG_CR_HW0_EN_Msk) : (ADC_TRIG_CR_HW1_EN_Msk));
  }
  else
  {
    ADCx->TRIG_CR &= ~((HWTrigX == ADC_HW_TRIG0) ? (ADC_TRIG_CR_HW0_EN_Msk) : (ADC_TRIG_CR_HW1_EN_Msk));
  }

}

/**
 *******************************************************************************
  * @brief  ADCx hardware trigger config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  HWTrigX:Hardware trigger 0 or 1 select. @ref ADC_HWTrigX
  * @param  HWTrig.Hardware trigger parameter.
  *         @arg TrigSource.Trigger source. @ref ADC_Trig_Source
  *         @arg TrigChannel.Trigger channel. @ref ADC_Channel
  *         @arg TrigEnable.Enable or disable hardware trigger.
  * @retval None
 ******************************************************************************/
void ADC_HardwareTrigConfig(ADC_Type* ADCx, ADC_HWTrigX HWTrigX, ADC_HWTrigStruct ADC_HWTrig)
{
  uint32_t tmpReg = 0UL;

  tmpReg = ADCx->TRIG_CR;

  /* Configure ADC hardware trigger 0. */
  if(HWTrigX == ADC_HW_TRIG0)
  {
    tmpReg &= ~ADC_TRIG_CR_HW0_CH_Msk;
    tmpReg &= ~ADC_TRIG_CR_HW0_SRC_Msk;

    tmpReg |= (ADC_HWTrig.TrigSource << ADC_TRIG_CR_HW0_SRC_Pos);
    tmpReg |= (ADC_HWTrig.TrigChannel << ADC_TRIG_CR_HW0_CH_Pos);

    if(ADC_HWTrig.TrigEnable != DISABLE)
    {
      tmpReg |= ADC_TRIG_CR_HW0_EN_Msk;
    }
    else
    {
      tmpReg &= ~ADC_TRIG_CR_HW0_EN_Msk;
    }
  }
  else   /* Configure ADC hardware trigger 1. */
  {
    tmpReg &= ~ADC_TRIG_CR_HW1_CH_Msk;
    tmpReg &= ~ADC_TRIG_CR_HW1_SRC_Msk;

    tmpReg |= (ADC_HWTrig.TrigSource << ADC_TRIG_CR_HW1_SRC_Pos);
    tmpReg |= (ADC_HWTrig.TrigChannel << ADC_TRIG_CR_HW1_CH_Pos);

    if(ADC_HWTrig.TrigEnable != DISABLE)
    {
      tmpReg |= ADC_TRIG_CR_HW1_EN_Msk;
    }
    else
    {
      tmpReg &= ~ADC_TRIG_CR_HW1_EN_Msk;
    }
  }

  ADCx->TRIG_CR = tmpReg;
}

/**
 *******************************************************************************
  * @brief  ADCx inject channel config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  INJ_Ch. @ref ADC_Channel
  * @retval None
 ******************************************************************************/
void ADC_InjectChannelConfig(ADC_Type* ADCx, uint8_t INJ_Ch)
{
  /* Write inject control register start bit 0 and inject channel to INJ_Ch. */
  ADCx->INJ_CR = (uint32_t)(INJ_Ch << ADC_INJ_CR_CH_Pos);

}

/**
 *******************************************************************************
  * @brief  ADCx start inject conversion.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval None
 ******************************************************************************/
void ADC_InjectStart(ADC_Type* ADCx)
{
  ADCx->INJ_CR |= ADC_INJ_CR_START_Msk;
}

/**
 *******************************************************************************
  * @brief  ADCx analog watchdog config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ADC_AWDGConfig:Analog watchdog parameter @ref ADC_AnalogWatchdogStruct
  *         @arg LowerThreshold:Analog watchdog lower threshold.
  *         @arg HighThreshold:Analog watchdog higher threshold.
  *         @arg AWDUpperLimitEnable:Analog watchdog higher threshold enable.
  *         @arg AWDLowerLimitEnable:Analog watchdog lower threshold enable.
  *         @arg AWDWindowLimitEnable:Analog watchdog window threshold enable.
  * @retval None
 ******************************************************************************/
void ADC_AnalogWatchdogConfig(ADC_Type* ADCx, ADC_AnalogWatchdogStruct* ADC_AWDGConfig)
{
  ADCx->AWD_TH = (uint32_t)(ADC_AWDGConfig->LowerThreshold | (uint32_t)(ADC_AWDGConfig->HighThreshold << ADC_AWD_TH_HT_Pos));

  /* Configure ADC analog watchdog lower limit enable. */
  if(ADC_AWDGConfig->AWDLowerLimitEnable != DISABLE)
  {
    ADCx->AWD_CR |= ADC_AWD_CR_WL_Msk;
  }
  else
  {
    ADCx->AWD_CR &= ~ADC_AWD_CR_WL_Msk;
  }

  /* Configure ADC analog watchdog upper limit enable. */
  if(ADC_AWDGConfig->AWDUpperLimitEnable != DISABLE)
  {
    ADCx->AWD_CR |= ADC_AWD_CR_WH_Msk;
  }
  else
  {
    ADCx->AWD_CR &= ~ADC_AWD_CR_WH_Msk;
  }

  /* Configure ADC analog watchdog window limit enable. */
  if(ADC_AWDGConfig->AWDWindowLimitEnable != DISABLE)
  {
    ADCx->AWD_CR |= ADC_AWD_CR_WM_Msk;
  }
  else
  {
    ADCx->AWD_CR &= ~ADC_AWD_CR_WM_Msk;
  }
}

/**
 *******************************************************************************
  * @brief  ADCx analog watchdog channel enable or disable.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  channel:Analog watchdog channel @ref ADC_Channel.
  * @param  NewState:Enable or disable
  * @retval None
 ******************************************************************************/
void ADC_AnalogWatchdogChannelCmd(ADC_Type* ADCx, uint8_t channel, FunctionalState NewState)
{
  if(NewState != DISABLE)
  {
    ADCx->AWD_CR |= (ADC_AWD_CR_EN0_Msk << channel);
  }
  else
  {
    ADCx->AWD_CR &= ~(ADC_AWD_CR_EN0_Msk << channel);
  }
}

/**
 *******************************************************************************
  * @brief  ADCx scan mode channel config.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  ScanChannel:ADC scan channel @ref ADC_SCAN_Channel.
  * @param  ADC_Channel:ADC input channel. @ref ADC_Channel.
  * @retval None
 ******************************************************************************/
void ADC_ScanChannelConfig(ADC_Type* ADCx, uint8_t ScanChannel, uint8_t ADC_Channel)
{
  if(ScanChannel < ADC_SCAN_Channel_6)
  {
    ADCx->SCAN_SQR0 &= ~(ADC_SCAN_SQR0_SQ0_CH_Msk << 4UL * ScanChannel);

    ADCx->SCAN_SQR0 |= (uint32_t)(ADC_Channel << (ADC_SCAN_SQR0_SQ0_CH_Pos + 4UL * ScanChannel));
  }
  else
  {
    ScanChannel -= ADC_SCAN_Channel_6;

    ADCx->SCAN_SQR1 &= ~(ADC_SCAN_SQR1_SQ6_CH_Msk << 4UL * ScanChannel);

    ADCx->SCAN_SQR1 |= (uint32_t)(ADC_Channel << (ADC_SCAN_SQR1_SQ6_CH_Pos + 4UL * ScanChannel));
  }
}

/**
 *******************************************************************************
  * @brief  Get ADCx single channel sample value.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval ADCx single channel sample value.
 ******************************************************************************/
uint16_t ADC_GetSingleData(ADC_Type* ADCx)
{
  return (uint16_t)ADCx->DR_SINGLE;
}

/**
 *******************************************************************************
  * @brief  Get ADCx inject channel sample value.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval ADCx inject channel sample value.
 ******************************************************************************/
uint16_t ADC_GetInjectData(ADC_Type* ADCx)
{
  return (uint16_t)ADCx->DR_INJ;
}

/**
 *******************************************************************************
  * @brief  Get ADCx hardware trigger 0 channel sample value.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval ADCx hardware trigger 0 channel sample value.
 ******************************************************************************/
uint16_t ADC_GetHWTrig0Data(ADC_Type* ADCx)
{
  return (uint16_t)ADCx->DR_TRIG0;
}

/**
 *******************************************************************************
  * @brief  Get ADCx hardware trigger 1 channel sample value.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @retval ADCx hardware trigger 0 channel sample value.
 ******************************************************************************/
uint16_t ADC_GetHWTrig1Data(ADC_Type* ADCx)
{
  return (uint16_t)ADCx->DR_TRIG1;
}

/**
 *******************************************************************************
  * @brief  Get ADCx scan mode channel sample value.
  * @param  ADCx: where x can be 0 or 1 to select the ADC peripheral.
  * @param  Channel:ADC scan channel. @ref ADC_SCAN_Channel
  * @retval ADCx single channel sample value.
 ******************************************************************************/
uint16_t ADC_GetScanData(ADC_Type* ADCx, uint8_t Channel)
{
  return (uint16_t)ADCx->DR_SCAN[Channel];
}
